package com.yilin.tms.gps.service.impl;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.yilin.commons.encrypt.SM2WithSM3Utils;
import com.yilin.commons.exception.BusinessException;
import com.yilin.commons.util.ArrayUtil;
import com.yilin.commons.util.DateTimeUtil;
import com.yilin.commons.util.JsonUtil;
import com.yilin.tms.core.commons.utils.ParamUtil;
import com.yilin.tms.core.entity.gps.Location;
import com.yilin.tms.core.entity.gps.hyb.*;
import com.yilin.tms.core.entity.order.transit.TransitOrder;
import com.yilin.tms.core.entity.user.hatch.HatchHyb;
import com.yilin.tms.core.remote.IMessageRemote;
import com.yilin.tms.core.remote.IOrderRemote;
import com.yilin.tms.core.remote.IUserRemote;
import com.yilin.tms.gps.service.IGpsHybService;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *
 */
@Service
@Transactional
public class GpsHybService implements IGpsHybService {
    // 用于存放孵化配置，不反复请求数据
    private final Map<String, HatchHyb> hatchHybMap = new HashMap<>();

    @Resource
    IUserRemote userRemote;
    @Resource
    IMessageRemote messageRemote;
    @Resource
    IOrderRemote orderRemote;

    private String hybBaseUrl = "https://agent.haoyunbao56.com";

    /**
     * 获取孵化配置：注意，只获取一次，重新设置后必须重启服务
     */
    @Override
    public HatchHyb getHatchGaode(String platId) {
        if (hatchHybMap.containsKey(platId)) return hatchHybMap.get(platId);
        HatchHyb gaodeMap = ParamUtil.isSuccess(userRemote.getHybHatch(platId));
        if (gaodeMap == null) throw new BusinessException("平台未初始好运宝地图API配置!");
        hatchHybMap.put(platId, gaodeMap);
        return gaodeMap;
    }

    /**
     * 绑定设备号
     */
    @Override
    public HybReturn<Object> bindVehicleDevice(String platId, String deviceId, String vehicleNumber) {
        Map<String, Object> param = new HashMap<>();
        param.put("device", deviceId);
        param.put("vehicleNumber", vehicleNumber);
        return hybPost("/shipping_fence/deviceVehicleBind", platId, param, new TypeToken<HybReturn<Object>>() {
        });
    }

    /**
     * 设备解绑
     */
    @Override
    public HybReturn<Object> unBindVehicleDevice(String platId, String deviceId, String vehicleNumber) {
        Map<String, Object> param = new HashMap<>();
        param.put("device", deviceId);
        param.put("vehicleNumber", vehicleNumber);
        return hybPost("/shipping_fence/deviceVehicleUnbinding", platId, param, new TypeToken<HybReturn<Object>>() {
        });
    }

    /**
     * 配置围栏
     */
    @Override
    public HybReturn<List<FenceResult>> storeDevicePolygon(String platId, String transportNo, String vehicleNumber, String driverName, List<FenceInfoDTO> fenceInfoList) {
        Map<String, Object> param = new HashMap<>();
        param.put("shippingNoteNumber", transportNo);
        param.put("serialNumber", "0000");
        param.put("driverName", driverName);
        param.put("vehicleNumber", vehicleNumber);
        param.put("fenceInfoList", fenceInfoList);
        return hybPost("/shipping_fence/device_store_polygon", platId, param, new TypeToken<HybReturn<List<FenceResult>>>() {
        });
    }

    /**
     * 取消围栏
     */
    @Override
    public HybReturn<FenceResult> deleteStoreDevicePolygon(String platId, String transportNo) {
        Map<String, Object> param = new HashMap<>();
        param.put("shippingNoteNumber", transportNo);
        param.put("serialNumber", "0000");
        return hybPost("/shipping_fence/delete", platId, param, new TypeToken<HybReturn<FenceResult>>() {
        });
    }

    /**
     * 获取围栏
     */
    @Override
    public HybReturn<ShippingFence> getDevicePolygon(String platId, String transportNo) {
        Map<String, Object> param = new HashMap<>();
        param.put("shippingNoteNumber", transportNo);
        param.put("serialNumber", "0000");
        return hybPost("/shipping_fence/pull", platId, param, new TypeToken<HybReturn<ShippingFence>>() {
        });
    }

    /**
     * 接收围栏实时推送
     * 暂时只做通知处理
     */
    @Override
    public HybReturn<Object> pushDevicePolygon(ShippingFence shippingFence) {
        TransitOrder transitOrder = ParamUtil.isSuccess(orderRemote.getTransitOrderByNo(shippingFence.getShippingNoteNumber()));
        List<FenceInfoDTO> fenceTriggerList = shippingFence.getFenceTriggerList();
        List<String> stringList = ArrayUtil.fieldAdd(fenceTriggerList, obj -> obj.getFenceType() == 1
                ? String.format("装货围栏（%s）", obj.getAddress())
                : String.format("卸货围栏（%s）", obj.getAddress())
        );
        String message = "尊敬的司机用户您好！你的好运宝设备已成功触发电子围栏：" + String.join("；", stringList) + "，请即时处理订单信息！";
        messageRemote.sendOrderNotify(transitOrder.getTransitTruckUserId(), message, String.format("transOrder?transitOrderId=%s", transitOrder.getId()));
        return new HybReturn<>(0, "围栏接收成功");
    }

    /**
     * 获取轨迹（通过运单号）
     */
    @Override
    public HybReturn<List<DeviceTrack>> getTrackByShipping(String platId, String transportNo) {
        Map<String, Object> param = new HashMap<>();
        param.put("shippingNoteNumber", transportNo);
        param.put("serialNumber", "0000");
        return hybPost("/device_track/get_track_by_shipping", platId, param, new TypeToken<HybReturn<List<DeviceTrack>>>() {
        });
    }

    /**
     * 获取轨迹（通过设备号）
     */
    @Override
    public HybReturn<List<DeviceTrack>> getTrackByDeviceId(String platId, String deviceId, Long startTime, Long endTime) {
        Map<String, Object> param = new HashMap<>();
        param.put("device", deviceId);
        param.put("startTime", startTime);//秒
        param.put("endTime", endTime);//秒
        return hybPost("/device_track/get_track", platId, param, new TypeToken<HybReturn<List<DeviceTrack>>>() {
        });
    }

    /**
     * 批量获取轨迹（通过设备号）
     */
    @Override
    public List<HybReturn<List<DeviceTrack>>> getTracksByDeviceId(String platId, String[] deviceIds, Long startTime, Long endTime) {
        HatchHyb hatchHyb = getHatchGaode(platId);
        List<Map<String, Object>> list = new ArrayList<>();
        for (String deviceId : deviceIds) {
            Map<String, Object> param = new HashMap<>();
            param.put("device", deviceId);
            param.put("startTime", startTime);//秒
            param.put("endTime", endTime);//秒
            param.put("sign", SM2WithSM3Utils.sign(hatchHyb.getPrivateKey(), JsonUtil.objectToJson(param)));
            list.add(param);
        }
        return hybPost("/devices_track/get_track", platId, list, new TypeToken<List<HybReturn<List<DeviceTrack>>>>() {
        });
    }

    /**
     * 获取设备信息（通过设备号）
     */
    @Override
    public HybReturn<EquipmentInfo> getTrackDeviceInfo(String platId, String deviceId) {
        Map<String, Object> param = new HashMap<>();
        param.put("device", deviceId);
        return hybPost("/device_track/fetch_device_info", platId, param, new TypeToken<HybReturn<EquipmentInfo>>() {
        });
    }

    /**
     * 批量获取设备信息（通过设备号）
     */
    @Override
    public List<HybReturn<EquipmentInfo>> getTrackDeviceInfos(String platId, String[] deviceIds) {
        HatchHyb hatchHyb = getHatchGaode(platId);
        List<Map<String, Object>> list = new ArrayList<>();
        for (String deviceId : deviceIds) {
            Map<String, Object> param = new HashMap<>();
            param.put("device", deviceId);
            param.put("sign", SM2WithSM3Utils.sign(hatchHyb.getPrivateKey(), JsonUtil.objectToJson(param)));
            list.add(param);
        }
        return hybPost("/device_track/fetch_devices_info", platId, list, new TypeToken<List<HybReturn<EquipmentInfo>>>() {
        });
    }


    /**
     * 批量获取设备信息（通过设备号）
     */
    @Override
    public List<Location> hybTrack2Locations(List<DeviceTrack> deviceTrackList) {
        List<Location> locationList = new ArrayList<>();
        for (DeviceTrack deviceTrack : deviceTrackList) {
            Location location = new Location();
            location.setmTime(DateTimeUtil.getTimeToDate(deviceTrack.getLocateTime() * 1000));
            location.setmLatitude(deviceTrack.getLat());
            location.setmLongitude(deviceTrack.getLng());
            location.setmSpeed(deviceTrack.getSpeed());
            location.setmBearing(deviceTrack.getDirection());
            locationList.add(location);
        }
        return locationList;
    }


    //公共请求方法
    public <T> HybReturn<T> hybPost(String path, String platId, Map<String,Object> param, TypeToken<HybReturn<T>> typeToken) {
        return JsonUtil.jsonToObject(hybPost( path,  platId,  param), typeToken);
    }
    public <T> List<HybReturn<T>> hybPost(String path, String platId, List<Map<String,Object>> param, TypeToken<List<HybReturn<T>>> typeToken) {
        return JsonUtil.jsonToObject(hybPost( path,  platId,  param), typeToken);
    }
    public String hybPost(String path, String platId, Object param) {
        HatchHyb hatchHyb = getHatchGaode(platId);
        Gson gson = new Gson();
        String json = gson.toJson(param);
        String signedData = SM2WithSM3Utils.sign(hatchHyb.getPrivateKey(), json);
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response;
        HttpPost httpPost;
        try {
            httpPost = new HttpPost(hybBaseUrl + path);
            httpPost.addHeader("X-AGENT-ID", hatchHyb.getAgentId());
            httpPost.addHeader("X-SIGNATURE", signedData);
            StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
            httpPost.setEntity(entity);
            response = httpClient.execute(httpPost);
            return EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            throw new BusinessException("未知错误");
        }
    }


}
